"""
新电信抢话费

环境变量chinaTelecomAccount，值为：账号#密码

cron: 57 23 * * *
const $ = new Env("电信凌晨云宝兑换");

青龙环境变量：
1. chinaTelecomAccount: 账号#密码，多账号换行
2. reqNUM: 重试次数，【默认2次，设置太大的重试次数，可能触发风控】

依赖安装：
1. pip3 install requests
2. pip3 install aiohttp
3. pip3 install pycryptodome
4. pip3 install pyexecjs
5. pip3 install lxml
6. pip3 install httpx
"""
#!/usr/bin/env python3
# ================ 本地配置区域 ================
# 测试开关配置
TEST_MODE = False  # True为测试模式，False为正式模式

# 测试账号配置（支持多账号，每行一个）
TEST_ACCOUNTS = """
"""
# ================ 导入区域 ================
import os
import re
import sys
import ssl
import time
import json
import execjs
import base64
import random
import certifi
import aiohttp
import asyncio
import certifi
import datetime
import requests
import binascii
from lxml import etree
from http import cookiejar
from Crypto.Cipher import AES
from Crypto.Cipher import DES3
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
from Crypto.Util.Padding import pad, unpad
from aiohttp import ClientSession, TCPConnector
from concurrent.futures import ThreadPoolExecutor
import subprocess

# 运行配置
MAX_RETRIES = 3  # 最大重试次数
RATE_LIMIT = 10  # 每秒请求数限制
run_num = os.environ.get('reqNUM') or "2"  # 重试次数
TEST_HOUR = 23

class RateLimiter:
    def __init__(self, rate_limit):
        self.rate_limit = rate_limit
        self.tokens = rate_limit
        self.updated_at = time.monotonic()

    async def acquire(self):
        while self.tokens < 1:
            self.add_new_tokens()
            await asyncio.sleep(0.1)
        self.tokens -= 1

    def add_new_tokens(self):
        now = time.monotonic()
        time_since_update = now - self.updated_at
        new_tokens = time_since_update * self.rate_limit
        if new_tokens > 1:
            self.tokens = min(self.tokens + new_tokens, self.rate_limit)
            self.updated_at = now

class AsyncSessionManager:
    def __init__(self):
        self.session = None
        self.connector = None

    async def __aenter__(self):
        ssl_context = ssl.create_default_context(cafile=certifi.where())
        ssl_context.set_ciphers('DEFAULT@SECLEVEL=1')
        self.connector = TCPConnector(ssl=ssl_context, limit=1000)
        self.session = ClientSession(connector=self.connector)
        return self.session

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        await self.session.close()
        await self.connector.close()

async def retry_request(session, method, url, **kwargs):
    for attempt in range(MAX_RETRIES):
        try:
            await asyncio.sleep(1)
            async with session.request(method, url, **kwargs) as response:
                return await response.json()
                # return await response.json()

        except (aiohttp.ClientConnectionError, aiohttp.ServerTimeoutError) as e:
            print(f"请求失败，第 {attempt + 1} 次重试: {e}")
            if attempt == MAX_RETRIES - 1:
                raise
            await asyncio.sleep(2 ** attempt)

class BlockAll(cookiejar.CookiePolicy):
    return_ok = set_ok = domain_return_ok = path_return_ok = lambda self, *args, **kwargs: False
    netscape = True
    rfc2965 = hide_cookie2 = False

def log(message, notify=False, level="INFO"):
    """统一的日志输出函数
    Args:
        message: 日志消息
        notify: 是否需要通知，默认False
        level: 日志级别，默认INFO
    """
    current_time = datetime.datetime.now().strftime("%H:%M:%S.%f")[:-3]
    level_color = {
        "INFO": "",
        "SUCCESS": "\033[92m",  # 绿色
        "WARNING": "\033[93m",  # 黄色
        "ERROR": "\033[91m",    # 红色
        "DEBUG": "\033[94m",    # 蓝色
    }
    reset_color = "\033[0m"
    
    # 格式化手机号显示
    message = re.sub(r'1\d{2}(\d{4})\d{4}', r'1**\1****', message)
    
    # 如果是详细的JSON数据，只显示关键信息
    if isinstance(message, str) and len(message) > 200:
        try:
            data = json.loads(message)
            if isinstance(data, dict):
                if 'rightsStatus' in data:
                    message = f"状态: {data['rightsStatus']}"
                    if 'data' in data and isinstance(data['data'], dict):
                        if 'righstName' in data['data']:
                            message += f", 权益: {data['data']['righstName']}"
                        if 'costCoin' in data['data']:
                            message += f", 金豆: {data['data']['costCoin']}"
        except:
            message = message[:200] + "..."
    
    color = level_color.get(level, "")
    print(f"{color}[{current_time}] [{level}] {message}{reset_color}")

def printn(message):
    """保持向后兼容的print函数"""
    log(message)

context = ssl.create_default_context()
context.set_ciphers('DEFAULT@SECLEVEL=1')  # 低安全级别0/1
context.check_hostname = False  # 禁用主机
context.verify_mode = ssl.CERT_NONE  # 禁用证书

class DESAdapter(requests.adapters.HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        kwargs['ssl_context'] = context
        return super().init_poolmanager(*args, **kwargs)

requests.packages.urllib3.disable_warnings()
# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
ss = requests.session()
ss.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","Referer":"https://wapact.189.cn:9001/JinDouMall/JinDouMall_independentDetails.html"}
ss.mount('https://', DESAdapter())
ss.cookies.set_policy(BlockAll())
runTime = 0


key = b'1234567`90koiuyhgtfrdews'  
iv = 8 * b'\0'  

# RSA公钥
public_key_b64 = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBkLT15ThVgz6/NOl6s8GNPofdWzWbCkWnkaAm7O2LjkM1H7dMvzkiqdxU02jamGRHLX/ZNMCXHnPcW/sDhiFCBN18qFvy8g6VYb9QtroI09e176s+ZCtiv7hbin2cCTj99iUpnEloZm19lwHyo69u5UMiPMpq0/XKBO8lYhN/gwIDAQAB
-----END PUBLIC KEY-----'''

public_key_data = '''-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+ugG5A8cZ3FqUKDwM57GM4io6JGcStivT8UdGt67PEOihLZTw3P7371+N47PrmsCpnTRzbTgcupKtUv8ImZalYk65dU8rjC/ridwhw9ffW2LBwvkEnDkkKKRi2liWIItDftJVBiWOh17o6gfbPoNrWORcAdcbpk2L+udld5kZNwIDAQAB
-----END PUBLIC KEY-----'''

def get_first_three(value):
    # 处理数字情况
    if isinstance(value, (int, float)):
        return int(str(value)[:3])
    elif isinstance(value, str):
        return str(value)[:3]
    else:
        raise TypeError("error")

def run_Time(hour,miute,second):
    date = datetime.datetime.now()
    date_zero = datetime.datetime.now().replace(year=date.year, month=date.month, day=date.day, hour=hour, minute=miute, second=second)
    date_zero_time = int(time.mktime(date_zero.timetuple()))
    return date_zero_time

def encrypt(text):
    cipher = DES3.new(key, DES3.MODE_CBC, iv)
    ciphertext = cipher.encrypt(pad(text.encode(), DES3.block_size))
    return ciphertext.hex()

def decrypt(text):
    ciphertext = bytes.fromhex(text)
    cipher = DES3.new(key, DES3.MODE_CBC, iv)
    plaintext = unpad(cipher.decrypt(ciphertext), DES3.block_size)
    return plaintext.decode()

def b64(plaintext):
    public_key = RSA.import_key(public_key_b64)
    cipher = PKCS1_v1_5.new(public_key)
    ciphertext = cipher.encrypt(plaintext.encode())
    return base64.b64encode(ciphertext).decode()

def encrypt_para(plaintext):
    if not isinstance(plaintext, str):
        plaintext = json.dumps(plaintext)
    public_key = RSA.import_key(public_key_data)
    cipher = PKCS1_v1_5.new(public_key)
    ciphertext = cipher.encrypt(plaintext.encode())
    return binascii.hexlify(ciphertext).decode()

def encode_phone(text):
    encoded_chars = []
    for char in text:
        encoded_chars.append(chr(ord(char) + 2))
    return ''.join(encoded_chars)


def getApiTime(api_url):
        try:
             with requests.get(api_url) as response:
                if(not response or not response.text):
                    return time.time()
                json_data = json.loads(response.text)
                if (json_data.get("api")and json_data.get("api")not in("time") ):
                    timestamp_str = json_data.get('data', {}).get('t', '')
                else:
                    timestamp_str = json_data.get('currentTime', {})
                timestamp = int(timestamp_str) / 1000.0  # 将毫秒转为秒
                difftime=time.time()-timestamp
                return difftime;
        except Exception as e:
            print(f"获取时间失败: {e}")
            return 0;


def userLoginNormal(phone, password):
    try:
        alphabet = 'abcdef0123456789'
        uuid = [''.join(random.sample(alphabet, 8)),''.join(random.sample(alphabet, 4)),'4'+''.join(random.sample(alphabet, 3)),''.join(random.sample(alphabet, 4)),''.join(random.sample(alphabet, 12))]
        timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        loginAuthCipherAsymmertric = 'iPhone 14 15.4.' + uuid[0] + uuid[1] + phone + timestamp + password[:6] + '0$$$0.'
        
        for retry in range(3):  # 最多重试3次
            try:
                headers = {
                    "User-Agent": "CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1",
                    "Content-Type": "application/json",
                    "Accept": "application/json"
                }
                
                r = ss.post(
                    'https://appgologin.189.cn:9031/login/client/userLoginNormal',
                    headers=headers,
                    json={
                        "headerInfos": {
                            "code": "userLoginNormal",
                            "timestamp": timestamp,
                            "broadAccount": "",
                            "broadToken": "",
                            "clientType": "#9.6.1#channel50#iPhone 14 Pro Max#",
                            "shopId": "20002",
                            "source": "110003",
                            "sourcePassword": "Sid98s",
                            "token": "",
                            "userLoginName": phone
                        },
                        "content": {
                            "attach": "test",
                            "fieldData": {
                                "loginType": "4",
                                "accountType": "",
                                "loginAuthCipherAsymmertric": b64(loginAuthCipherAsymmertric),
                                "deviceUid": uuid[0] + uuid[1] + uuid[2],
                                "phoneNum": encode_phone(phone),
                                "isChinatelecom": "1",  
                                "systemVersion": "15.4.0",
                                "authentication": password
                            }
                        }
                    },
                    verify=certifi.where(),
                    timeout=15  # 增加超时时间
                )
                
                if not r.ok:
                    printn(f"{get_first_three(phone)} 登录请求失败: HTTP {r.status_code}")
                    continue
                    
                try:
                    r_json = r.json()
                except json.JSONDecodeError:
                    printn(f"{get_first_three(phone)} 登录响应解析失败")
                    continue
                
                if 'responseData' not in r_json or 'data' not in r_json['responseData']:
                    printn(f"{get_first_three(phone)} 登录响应格式错误: {r_json}")
                    continue
                    
                l = r_json['responseData']['data'].get('loginSuccessResult')
                if not l:
                    error_msg = r_json['responseData']['data'].get('loginFailureResult', {}).get('failReason', '未知原因')
                    printn(f"{get_first_three(phone)} 登录失败: {error_msg}")
                    if retry < 2:
                        time.sleep(2)  # 登录失败后等待2秒再重试
                    continue
                    
                ticket = get_ticket(phone, l['userId'], l['token'])
                if ticket:
                    printn(f"{get_first_three(phone)} 登录成功")
                    return ticket
                    
            except requests.exceptions.RequestException as e:
                printn(f"{get_first_three(phone)} 登录请求异常: {str(e)}")
                if retry < 2:
                    time.sleep(2)
                continue
                
        return False
        
    except Exception as e:
        printn(f"{get_first_three(phone)} 登录过程发生错误: {str(e)}")
        return False

async def exchangeForDay(phone, session, run_num, rid, stime):
    async def delayed_conversion(delay):
        await asyncio.sleep(delay)
        await conversionRights(phone, rid,session)
    tasks = [asyncio.create_task(delayed_conversion(i * stime)) for i in range(int(run_num))]
    await asyncio.gather(*tasks)
def get_ticket(phone, userId, token):
    try:
        for retry in range(3):  # 最多重试3次
            try:
                headers = {
                    'user-agent': 'CtClient;10.4.1;Android;13;22081212C;NTQzNzgx!#!MTgwNTg1',
                    'Content-Type': 'application/xml'
                }
                
                request_data = (
                    '<Request>'
                    '<HeaderInfos>'
                    f'<Code>getSingle</Code>'
                    f'<Timestamp>{datetime.datetime.now().strftime("%Y%m%d%H%M%S")}</Timestamp>'
                    '<BroadAccount></BroadAccount>'
                    '<BroadToken></BroadToken>'
                    '<ClientType>#9.6.1#channel50#iPhone 14 Pro Max#</ClientType>'
                    '<ShopId>20002</ShopId>'
                    '<Source>110003</Source>'
                    '<SourcePassword>Sid98s</SourcePassword>'
                    f'<Token>{token}</Token>'
                    f'<UserLoginName>{phone}</UserLoginName>'
                    '</HeaderInfos>'
                    '<Content>'
                    '<Attach>test</Attach>'
                    '<FieldData>'
                    f'<TargetId>{encrypt(userId)}</TargetId>'
                    '<Url>4a6862274835b451</Url>'
                    '</FieldData>'
                    '</Content>'
                    '</Request>'
                )
                
                r = ss.post(
                    'https://appgologin.189.cn:9031/map/clientXML',
                    data=request_data,
                    headers=headers,
                    verify=certifi.where(),
                    timeout=15
                )
                
                if not r.ok:
                    printn(f"{get_first_three(phone)} 获取ticket请求失败: HTTP {r.status_code}")
                    continue
                
                tk = re.findall('<Ticket>(.*?)</Ticket>', r.text)
                if not tk:
                    printn(f"{get_first_three(phone)} 未找到ticket信息")
                    if retry < 2:
                        time.sleep(2)
                    continue
                
                try:
                    ticket = decrypt(tk[0])
                    printn(f"{get_first_three(phone)} 成功获取ticket")
                    return ticket
                except Exception as e:
                    printn(f"{get_first_three(phone)} ticket解密失败: {str(e)}")
                    continue
                    
            except requests.exceptions.RequestException as e:
                printn(f"{get_first_three(phone)} 获取ticket请求异常: {str(e)}")
                if retry < 2:
                    time.sleep(2)
                continue
                
        return False
        
    except Exception as e:
        printn(f"{get_first_three(phone)} 获取ticket过程发生错误: {str(e)}")
        return False

async def exchange(s, phone, title, aid,jsexec, ckvalue):
    try:
        url="https://wapact.189.cn:9001/gateway/standExchange/detailNew/exchange"
        # getck = await asyncio.to_thread(jsexec.call, "getck") # 两种方式，一种用ck，一种用后缀
        # getck = getck.split(';')[0].split('=')
        # ckvalue[getck[0]] = getck[1]

        # async with s.post(url, cookies=ckvalue, json={"activityId": aid}) as response:

        # 通过 retry_request 实现重试机制
        # response = await retry_request(s, 'POST', get_url, cookies=ckvalue, json={"activityId": aid})

        get_url = await asyncio.to_thread(jsexec.call,"getUrl", "POST",url)
        async with s.post(get_url, cookies=ckvalue, json={"activityId": aid}) as response:
            pass
    except Exception as e:
        print(e)



async def check(s,item,ckvalue):
    checkGoods = s.get('https://wapact.189.cn:9001/gateway/stand/detailNew/check?activityId=' + item, cookies=ckvalue).json()
    return checkGoods

def write_success_log(phone, data):
    """将兑换成功的记录写入日志文件
    Args:
        phone: 手机号
        data: 兑换返回的数据
    """
    try:
        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_file = "exchange_success.log"
        
        # 获取权益名称和其他相关信息
        rights_name = data.get('data', {}).get('righstName', '未知权益')
        rights_status = data.get('rightsStatus', '兑换成功')
        cost_coin = data.get('data', {}).get('costCoin', '0')
        
        # 格式化日志内容
        log_content = f"[{current_time}] 账号: {phone}, 状态: {rights_status}, 权益: {rights_name}, 金豆: {cost_coin}\n"
        
        # 追加模式写入日志
        with open(log_file, 'a', encoding='utf-8') as f:
            f.write(log_content)
    except Exception as e:
        log(f"写入日志文件失败: {str(e)}", level="ERROR")

async def conversionRights(phone, aid, session):
    try:
        ruishu_cookies = get_ruishu_cookies()
        if not ruishu_cookies:
            log(f"账号 {get_first_three(phone)}: 无法获取 Ruishu cookies", level="ERROR")
            return

        value = {
            "phone": phone,
            "rightsId": aid,
            "receiveCount": "1"
        }
        paraV = encrypt_para(value)

        log(f"账号 {get_first_three(phone)}: 开始兑换权益", level="INFO")

        response = session.post(
            'https://wappark.189.cn/jt-sign/paradise/getConversionRights',
            json={"para": paraV},
            cookies=ruishu_cookies
        )

        data = response.json()
        log(f"账号 {get_first_three(phone)}: {json.dumps(data, ensure_ascii=False)}", level="DEBUG")

        rights_status = data.get('rightsStatus', '')
        if '已兑换' in rights_status or '已领取' in rights_status:
            log(f"账号 {get_first_three(phone)}: 该权益已经兑换或领取", level="WARNING")
            return False
            
        if data.get('code') == 200 or '兑换成功' in str(data):
            msg = f"账号 {get_first_three(phone)}: 兑换成功"
            log(msg, notify=True, level="SUCCESS")
            # 记录成功兑换到日志文件
            write_success_log(phone, data)
            return True
        else:
            error_msg = data.get('msg') or data.get('resoultMsg') or data.get('error') or '未知错误'
            log(f"账号 {get_first_three(phone)}: 兑换失败 - {error_msg}", level="ERROR")
            return False

    except Exception as e:
        log(f"账号 {get_first_three(phone)}: 兑换请求发生错误: {str(e)}", level="ERROR")
        return False

async def getLevelRightsList(phone, session):
    try:
        # 获取 Ruishu cookies
        ruishu_cookies = get_ruishu_cookies()
        if not ruishu_cookies:
            print("无法获取 Ruishu cookies")
            return None

        value = {
            "phone": phone
        }
        paraV = encrypt_para(value)

        # 使用 Ruishu cookies 发送请求
        response = session.post(
            'https://wappark.189.cn/jt-sign/paradise/getLevelRightsList',  # 更正URL
            json={"para": paraV},
            cookies=ruishu_cookies
        )

        data = response.json()
        if data.get('code') == 401:
            print(f"获取失败:{data},原因大概是sign过期了")
            return None

        current_level = int(data.get('currentLevel', 0))
        key_name = 'V' + str(current_level)
        ids = [item['id'] for item in data.get(key_name, []) if item.get('name') == '话费']
        return ids[0] if ids else None

    except Exception as e:
        print(f"获取失败,重试一次: {str(e)}")
        try:
            # 重试时重新获取 Ruishu cookies
            ruishu_cookies = get_ruishu_cookies()
            if not ruishu_cookies:
                print("重试时无法获取 Ruishu cookies")
                return None

            paraV = encrypt_para(value)
            response = session.post(
                'https://wappark.189.cn/jt-sign/paradise/getLevelRightsList',  # 更正URL
                json={"para": paraV},
                cookies=ruishu_cookies
            )

            data = response.json()
            if data.get('code') == 401:
                print(f"重试获取失败:{data},原因大概是sign过期了")
                return None

            current_level = int(data.get('currentLevel', 0))
            key_name = 'V' + str(current_level)
            ids = [item['id'] for item in data.get(key_name, []) if item.get('name') == '话费']
            return ids[0] if ids else None

        except Exception as e:
            print(f"重试也失败了: {str(e)}")
            return None

def get_ruishu_cookies():
    try:
        # 获取当前文件所在目录
        current_dir = os.path.dirname(os.path.abspath(__file__))
        ruishu_path = os.path.join(current_dir, 'Ruishu.py')

        # 执行 Ruishu.py 并获取输出
        result = subprocess.run([sys.executable, ruishu_path],
                              capture_output=True,
                              text=True)

        if result.returncode != 0:
            print(f"Ruishu.py 执行错误: {result.stderr}")
            return None

        # 解析输出的 JSON
        cookies = json.loads(result.stdout.strip())
        return cookies

    except Exception as e:
        print(f"获取 Ruishu cookies 时发生错误: {str(e)}")
        return None

async def getSign(ticket, session):
    try:
        # 获取 Ruishu cookies
        ruishu_cookies = get_ruishu_cookies()
        if not ruishu_cookies:
            print("无法获取 Ruishu cookies")
            return None

        # 合并现有的 cookies 和 Ruishu cookies
        cookies = {**ruishu_cookies}

        # 使用合并后的 cookies 发送请求
        response = session.get(
            'https://wappark.189.cn/jt-sign/ssoHomLogin?ticket=' + ticket,
            cookies=cookies
        ).json()

        if response.get('resoultCode') == '0':
            sign = response.get('sign')
            return sign
        else:
            print(f"获取sign失败[{response.get('resoultCode')}]: {response}")
    except Exception as e:
        print(f"getSign 发生错误: {str(e)}")
    return None

async def qgNight(phone, ticket, timeDiff,isTrue):
    if isTrue:
        runTime = run_Time(23,59,3)
    else:
        # runTime = run_Time(0,0,0) + 0.65
        runTime = 0

    if runTime >(time.time()+timeDiff):
        difftime = runTime - time.time() - timeDiff
        print(f"当前时间:{str(datetime.datetime.now())[11:23]},跟设定的时间不同,等待{difftime}秒开始兑换每天一次的")
        await asyncio.sleep(difftime)
    session = requests.Session()
    session.mount('https://', DESAdapter())
    session.verify = False  # 禁用证书验证
    sign =await getSign(ticket,session)
    if sign:
        # print(f"当前时间:{str(datetime.datetime.now())[11:23]}获取到了Sign:"+sign)
        session.headers={"User-Agent":"Mozilla/5.0 (Linux; Android 13; 22081212C Build/TKQ1.220829.002) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.97 Mobile Safari/537.36","sign":sign}
    else:
        print("未获取sign。")
        return
    rightsId =await getLevelRightsList(phone,session)
    if rightsId:
        print("获取到了rightsId:"+rightsId)
    else:
        print("未能获取rightsId。")
        return
    # await asyncio.sleep(10)直接延迟也行，或者用下面的等待一段时间。之所以这样是要先获取sign省一些步骤。
    if isTrue:
        runTime2 = run_Time(23,59,59) + 0.7
        difftime = runTime2 - time.time() - timeDiff
        printn(f"等待{difftime}s")
        await asyncio.sleep(difftime)
    await exchangeForDay(phone,session,run_num,rightsId,0.1)
async def qgDay(phone, ticket,  timeDiff, isTrue):
    async with AsyncSessionManager() as s:
      pass
async def main(timeDiff,isTRUE,hour):
    tasks = []
    PHONES = os.environ.get('chinaTelecomAccount')
    if not PHONES:
        log("未设置账号信息", level="ERROR")
        return
        
    phone_list = [p.strip() for p in PHONES.split('\n') if p.strip()]
    log(f"共加载 {len(phone_list)} 个账号", level="INFO")
    
    for phoneV in phone_list:
        try:
            if '#' not in phoneV:
                log(f'账号格式错误，跳过: {phoneV}', level="WARNING")
                continue
                
            value = phoneV.split('#')
            if len(value) != 2:
                log(f'账号格式错误，跳过: {phoneV}', level="WARNING")
                continue
                
            phone, password = value[0].strip(), value[1].strip()
            if not phone or not password:
                log(f'账号或密码为空，跳过: {phoneV}', level="WARNING")
                continue
                
            log(f'账号 {get_first_three(phone)} 开始登录', level="INFO")
            ticket = userLoginNormal(phone,password)
            
            if ticket:
                log(f'账号 {get_first_three(phone)} 登录成功', level="SUCCESS")
                if hour > 15:
                    tasks.append(qgNight(phone, ticket, timeDiff, isTRUE))
                else:
                    tasks.append(qgDay(phone, ticket, timeDiff, isTRUE))
            else:
                log(f'账号 {get_first_three(phone)} 登录失败', level="ERROR")
        except Exception as e:
            log(f'账号 {get_first_three(phone)} 处理出错: {str(e)}', level="ERROR")
            continue
            
    if tasks:
        await asyncio.gather(*tasks)
    else:
        log("没有可执行的任务", level="WARNING")

if __name__ == "__main__":
    if os.path.exists('/ql/data/config/auth.json'):
        log("当前环境为青龙面板", level="INFO")
    
    if TEST_MODE and TEST_ACCOUNTS.strip():
        log("使用测试账号运行", level="INFO")
        os.environ['chinaTelecomAccount'] = TEST_ACCOUNTS.strip()
    
    if not os.environ.get('chinaTelecomAccount'):
        log("未设置环境变量chinaTelecomAccount，退出程序", level="ERROR")
        sys.exit(1)
        
    h = datetime.datetime.now().hour
    if TEST_MODE:
        h = TEST_HOUR
        log(f"测试模式：使用{h}点时段", level="INFO")
    log(f"当前运行时段: {h}点", level="INFO")
    
    if 10 > h > 0:
        log(f"当前时段为{h}点，准备抢十点场次", level="INFO")
        wttime = run_Time(9,59,8)
    elif 14 >= h >= 10:
        log(f"当前时段为{h}点，准备抢十四点场次", level="INFO")
        wttime = run_Time(13,59,8)
    else:
        log(f"当前时段为{h}点，准备抢凌晨场次", level="INFO")
        wttime = run_Time(23,58,58)
    
    isTRUE = not TEST_MODE
    
    if(wttime > time.time()):
        wTime = wttime-time.time()
        log(f"未到抢购时间，等待{wTime:.2f}秒", level="INFO")
        if isTRUE:
            log("注意：请先测试运行，根据自身情况设定重发次数和多账号数量，避免抢购时机过早或过晚。", level="WARNING")
            log("开始等待...", level="INFO")
            time.sleep(wTime)
            
    timeValue = 0
    timeDiff = timeValue if timeValue > 0 else 0
    
    try:
        asyncio.run(main(timeDiff, isTRUE, h))
        log("所有任务执行完毕!", level="SUCCESS")
    except KeyboardInterrupt:
        log("\n程序被用户中断", level="WARNING")
    except Exception as e:
        log(f"程序执行出错: {str(e)}", level="ERROR")
